package net.lesscoding.shop.service.impl;

import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import net.lesscoding.shop.common.Result;
import net.lesscoding.shop.entity.*;
import net.lesscoding.shop.enums.ShopCode;
import net.lesscoding.shop.exception.CastException;
import net.lesscoding.shop.mapper.OrderMapper;
import net.lesscoding.shop.mq.MqEntity;
import net.lesscoding.shop.remote.CouponFeignService;
import net.lesscoding.shop.remote.GoodsFeignService;
import net.lesscoding.shop.remote.UserFeignService;
import net.lesscoding.shop.service.OrderService;
import net.lesscoding.shop.utils.BigDecimalUtil;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;

/**
 * @author 24962
 * @description 针对表【trade_order】的数据库操作Service实现
 * @createDate 2024-06-07 15:16:06
 * 这类可以用Seata或者是创建好订单之后在进行扣减库存之类的
 */
@Slf4j
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order>
        implements OrderService {

    @Autowired
    private GoodsFeignService goodsService;

    @Autowired
    private UserFeignService userService;

    @Autowired
    private CouponFeignService couponService;

    @Autowired
    private OrderMapper orderMapper;

    @Value("${mq.order.topic:orderTopic}")
    private String topic;

    @Value("${mq.order.tag.cancel:order_cancel}")
    private String tag;

    @Autowired
    private RocketMQTemplate rocketMQTemplate;


    @Override
    public Result confirmOrder(Order order) {
        // 1. 校验订单
        User user = checkOrder(order);
        // 2. 生成预订单
        genPreOrder(order, user);
        try {
            // 3. 扣减库存
            reduceGoodsNum(order);
            // 4. 扣减优惠券
            updateCoupon(order);
            // 5. 使用余额
            reduceUserMoney(order);
            // 6. 确认订单
            updateOrderStatus(order);
            int i = 1/0;
            // 7. 返回成功状态
            return Result.success(true);
        } catch (Exception e) {
            // 1. 确认订单失败，发送消息
            MqEntity mqEntity = new MqEntity();
            mqEntity.setOrderId(order.getOrderId());
            mqEntity.setUserId(order.getUserId());
            mqEntity.setUserMoney(order.getMoneyPaid());
            mqEntity.setGoodsId(order.getGoodsId());
            mqEntity.setGoodsNum(order.getGoodsNumber());
            mqEntity.setCouponId(order.getCouponId());
            sendCancelOrder(topic, tag, order.getOrderId().toString(), JSON.toJSONString(mqEntity));
            // 2. 返回失败状态
            return Result.failed("confirm Failed");
        }
    }

    /**
     * 发送订单确认失败消息
     *
     * @param topic   mq的topic
     * @param tag     mq的tag
     * @param key     唯一key
     * @param msgBody 消息体
     */
    private void sendCancelOrder(String topic, String tag, String key, String msgBody) {
        Message message = new Message(topic, tag, key, msgBody.getBytes()        );
        try {
            log.info("发送消息 {}", JSON.toJSONString(message));
            rocketMQTemplate.getProducer().send(message);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }

    private void updateOrderStatus(Order order) {
        order.setOrderStatus(ShopCode.SHOP_ORDER_CONFIRM.getCode());
        order.setPayStatus(ShopCode.SHOP_ORDER_PAY_STATUS_NO_PAY.getCode());
        order.setConfirmTime(LocalDateTime.now());
        int effectRow = orderMapper.updateById(order);
        if (effectRow < 0) {
            CastException.cast(ShopCode.SHOP_ORDER_CONFIRM_FAIL);
        }
        log.info("订单{}确认完成", order.getOrderId());
    }

    private void reduceUserMoney(Order order) {
        if (order.getMoneyPaid() != null && BigDecimalUtil.moreThan(order.getMoneyPaid(), 0)) {
            UserMoneyLog userMoneyLog = new UserMoneyLog(order.getOrderId(),
                    order.getUserId(),
                    ShopCode.SHOP_USER_MONEY_PAID.getCode(),
                    order.getMoneyPaid());
            Result result = userService.updateUserMoney(userMoneyLog);
            if (result.getCode() != 200) {
                CastException.cast(ShopCode.SHOP_USER_MONEY_REDUCE_FAIL);
            }

            log.info("订单{}扣减余额成功", order.getOrderId());
        }
    }

    private void updateCoupon(Order order) {
        if (order.getCouponId() != null) {
            Coupon coupon = couponService.getById(order.getCouponId()).getData();
            coupon.setOrderId(order.getOrderId());
            coupon.setUsed(ShopCode.SHOP_COUPON_ISUSED.getCode());
            coupon.setUsedTime(LocalDateTime.now());
            coupon.setUserId(order.getUserId());
            boolean flag = couponService.updateById(coupon).getData();
            if (!flag) {
                CastException.cast(ShopCode.SHOP_COUPON_USE_FAIL);
            }
            log.info("优惠券使用完成");
        }
    }

    /**
     * 建议先锁库存，等会支付完成的时候在进行扣减
     *
     * @param order
     */
    private void reduceGoodsNum(Order order) {
        GoodsNumberLog goodsLog = new GoodsNumberLog(order.getOrderId(), order.getGoodsId(), order.getGoodsNumber());
        Result result = goodsService.reduceGoodsNum(goodsLog);
        if (result.getCode() != 200) {
            CastException.cast(ShopCode.SHOP_REDUCE_GOODS_NUM_FAIL);
        }
        log.info("订单{}扣减库存成功", order.getOrderId());
    }

    /**
     * 生成预订单
     *
     * @param order
     */
    private void genPreOrder(Order order, User user) {
        // 1. 订单状态为不可见
        order.setOrderStatus(ShopCode.SHOP_ORDER_NO_CONFIRM.getCode());
        // 2. 设置订单Id
        long orderId = IdUtil.getSnowflakeNextId();
        order.setOrderId(orderId);
        // 3. 核算订单运费
        BigDecimal shippingFee = calcShippingFee(order.getPayAmount());
        if (!BigDecimalUtil.equals(shippingFee, order.getShippingFee())) {
            CastException.cast(ShopCode.SHOP_ORDER_SHIPPINGFEE_INVALID);
        }
        // 4. 检验订单总金额
        BigDecimal orderAmount = order.getGoodsPrice().multiply(new BigDecimal(order.getGoodsNumber()));
        orderAmount.add(shippingFee);
        if (!BigDecimalUtil.equals(orderAmount, order.getOrderAmount())) {
            CastException.cast(ShopCode.SHOP_ORDERAMOUNT_INVALID);
        }
        // 5. 判断用户余额
        // 这里一般不会吧用户余额在前端传过来的吧
        BigDecimal moneyPaid = order.getMoneyPaid();
        if (moneyPaid != null) {
            // 用户余额
            if (BigDecimalUtil.lessOrEquals(moneyPaid, BigDecimal.ZERO)) {
                CastException.cast(ShopCode.SHOP_MONEY_PAID_LESS_ZERO);
            }
            if (BigDecimalUtil.moreThan(moneyPaid, user.getUserMoney())) {
                CastException.cast(ShopCode.SHOP_MONEY_PAID_INVALID);
            }
        } else {
            order.setMoneyPaid(BigDecimal.ZERO);
        }
        // 6. 优惠券处理
        Long couponId = order.getCouponId();
        if (couponId != null) {
            // 查询优惠券是否存在且未被使用
            Coupon coupon = couponService.getById(couponId).getData();
            if (coupon == null) {
                CastException.cast(ShopCode.SHOP_COUPON_NO_EXIST);
            }

            if (coupon.getUsed() == 1) {
                CastException.cast(ShopCode.SHOP_COUPON_ISUSED);
            }
            order.setCouponPaid(coupon.getCouponPrice());
        } else {
            order.setCouponPaid(BigDecimal.ZERO);
        }
        // 7. 核算支付金额
        BigDecimal payAmount = order.getPayAmount().subtract(order.getMoneyPaid()).subtract(order.getCouponPaid());
        order.setPayAmount(payAmount);
        // 8. 保存下单时间
        order.setAddTime(LocalDateTime.now());
        // 9. 入库
        orderMapper.insert(order);
        // 10. 返回订单id
    }

    /**
     * 运费
     *
     * @param payAmount
     */
    private BigDecimal calcShippingFee(BigDecimal payAmount) {
        return BigDecimalUtil.moreThan(payAmount, new BigDecimal(100)) ?
                BigDecimal.ZERO :
                BigDecimal.TEN;
    }

    /**
     * 校验订单
     *
     * @param order
     */
    private User checkOrder(Order order) {
        // 校验订单是否存在，
        if (order == null) {
            CastException.cast(ShopCode.SHOP_ORDER_INVALID);
        }
        // 校验订单中的商品是否存在
        Goods goods = goodsService.getById(order.getGoodsId()).getData();
        if (goods == null) {
            CastException.cast(ShopCode.SHOP_GOODS_NO_EXIST);
        }
        // 校验下单用户
        User user = userService.getById(order.getUserId()).getData();
        if (user == null) {
            CastException.cast(ShopCode.SHOP_USER_NO_EXIST);
        }
        // 校验订单金额
        BigDecimal orderPrice = goods.getGoodsPrice().multiply(BigDecimal.valueOf(order.getGoodsNumber()));
        if (!BigDecimalUtil.equals(order.getOrderAmount(), orderPrice)) {
            CastException.cast(ShopCode.SHOP_ORDERAMOUNT_INVALID);
        }
        // 校验库存
        if (order.getGoodsNumber() > goods.getGoodsNumber()) {
            CastException.cast(ShopCode.SHOP_GOODS_NUM_NOT_ENOUGH);
        }
        log.info("订单校验完成");
        return user;
    }
}




